package seqlist.动态数组实现;

import java.util.Arrays;

/**
 * 基于int的动态数组，根据元素的个数来动态调整数组大小
 */
public class MyArray {
    // 存储的元素任然是int[]
    private int[] data;
    //存储元素的有效个数
    private int size;

    //无参构造函数 如果用户没有主动输出空间大小，我们就自定义一个
    public MyArray(){
        this(10);
    }
    //有参构造函数
    public MyArray(int initCap){
        this.data = new int[initCap];
    }

    //添加数据功能： add
    public void add(int val){
        data[size] = val;
        size++;
        //当数组添加元素时，有可能会占满数组
        //所以这些我们需要判断是否需要扩容
        if(size == data.length){
            // 此时数组已满,扩容当前数组
            grow();
        }

    }

    /**
     * 对于外部的使用者来说，压根都不知道你MyArray这个类中还有个int[]，数组的扩容对外部也是不可见的
     * 置为private权限
     * 使数组增容，每次增加元素数组大小的两倍
     * 使用 Arrays.copyOf --需要头文件引入
     */
    private void grow() {
        // copyOf方法返回扩容后的新数组
        data = Arrays.copyOf(data, data.length * 2);
        System.out.println("扩容成功");
    }

    /**
     * 在 index 索引处 插入 val
     */
    public void add(int index, int val){
        //先判断给的索引值是否合理
        if(index < 0 || index > size){
            System.out.println("输入插入的索引值错误，请重新输入");
            return;
        }
        // 从当前最后一个有效元素开始向后搬移元素，把index位置空出来
        for (int i = size; i > index ; i--) {
            data[i] = data[i - 1];
        }
        data[index] = val;
        size ++;

        //继续判断插入一个元素后是否需要扩容
        if(size == data.length){
            grow();
        }

    }

    /**
     * 查询当前动态数组中第一个值为val的元素对应的索引
     * 若不存在，返回 -1，表示当前val不存在
     */
    public int getByValue(int val){
        for (int i = 0; i < size; i++) {
            if(data[i] == val)
                return i;
        }
        return -1;
    }
    //2. 第二种，查询当前动态数组中是否包含值为val的元素，若存在返回true，否则返回false
    public boolean contains(int val){
        if(getByValue(val) != -1){
            return true;
        }
        return false;
    }

    //3.第三种，查询当前动态数组中索引为index的元素值
    public int get(int index){
        //先判断给的索引值是否合理
        if(index < 0 || index >= size){
            System.out.println("输入查询的索引值错误，请重新输入");
            return - 1;
        }
        return data[index];
    }

    /**
     * 修改 index 位置的元素值改为 newValue，并返回修改前的值
     */
    public int set(int index, int newValue){
        //先判断给的索引值是否合理
        if(index < 0 || index >= size){
            System.out.println("输入修改的索引值错误，请重新输入");
            return - 1;
        }
        int rep = data[index];//保存要修改的值
        data[index] = newValue;
        return rep;
    }

    /**
     * 修改第一个值为 oldVal的元素改为 newValue,并返回索引下标
     */
    public int setVal(int oldVal, int newValue){

        for (int i = 0; i < size; i++) {
            if(data[i] == oldVal){
                data[i] = newValue;
                return i;
            }
        }
        System.out.println("没有这个元素存在，不能修改");
        return -1;
    }

    //删除
    /**
     * 1. 删除索引为 index 的元素,并返回删除前的元素
     */
    public int remove(int index){
        //先判断给的索引值是否合理
        if(index < 0 || index >= size){
            System.out.println("输入删除的索引值错误，请重新输入");
            return - 1;
        }

        //判断如果里面没东西可以删除了，就不做改变
        if(size <= 0)
            return -1;

        int rep = data[index];//保存要删除的元素值
        //这里需要从 前 向 后依次前移
        //移动次数是 size - 1 - index
        //注释：size - 1是最大元素的索引
        for (int i = index; i < size - 1; i++) {
            data[i] = data[i + 1];
        }
        size--;
        return rep;
    }
    //2. 头删 并返回删除的元素
    public int removeFirst(){
        return remove(0);
    }

    //3. 尾删除 并返回删除的元素
    public int removeLast(){
        return remove(size - 1);
    }

    //4. 删除第一个为 val的元素,并返回是否删除成功
    public boolean removeValue(int val){
        int tmp = getByValue(val);
        if(tmp != -1){
            int rep = data[tmp];
            remove(tmp);
            return true;
        }
        System.out.println("不存在这个元素");
        return false;
    }
    //5. 删除数组中所有为 val的元素

    public void removeAllValue(int val){

        for (int i = 0; i < size;) {

            if(data[i]  == val){
                remove(i);
            }else{
                i++;
            }

        }

    }


    /**
     * 因为println打印 对象 时会自动调用toString方法
     * 打印的却是地址，我们想要打印数组内容就要被toString方法
     * 进行重写，重定义。
     */
    //完成打印数组内容的功能 补充下toString的功能
    public String toString(){
        String rep = "[";
        for (int i = 0; i < size; i++) {
            // 此时取得是有效数据，使用size属性
            // size表示当前有效元素的下一个索引位置
            rep += data[i];
            //最后一位元素需要 逗号
            if(i != size - 1) {

                rep += ", ";
            }
        }
        rep += "]";
        return rep;
    }


}
